package com.company.common.auth.util;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSON;
import com.company.cloud.common.bean.DataMapEntity;
import com.company.cloud.common.bean.LoginUserInfo;
import com.company.cloud.common.constant.ApiAuthTypeEnum;
import com.company.cloud.common.constant.BaseReturnEnum;
import com.company.cloud.common.exception.BusinessException;
import com.company.cloud.common.redis.service.RedisUtils;
import com.company.cloud.common.utils.RegexUtils;
import com.company.cloud.common.utils.StrSplitUtils;
import com.company.common.auth.AuthSecurityManager;
import com.company.common.auth.handle.AuthHandle;

public class SecurityUrlUtils {

    private static String AuthCacheKey = "auth:url";
    private static String AuthCacheMapRegKey = "map:reg:key";


    /**
     * 初始化缓存
     */
    public static void initCache(Map<String, Set<String>> urls, RedisUtils redisUtils) {
        Map<String, String> authMap = new HashMap<String, String>();
        DataMapEntity regAuthMap = new DataMapEntity();

        if (!CollectionUtils.isEmpty(urls)) {
            for (String url : urls.keySet()) {
                Set<String> authTypes = urls.get(url);
                if (url.indexOf("*") == -1) {
                    authMap.put(url, StrSplitUtils.list2string(authTypes));
                } else {
                    regAuthMap.put(url, StrSplitUtils.list2string(authTypes));
                }
            }
        }

        if (!CollectionUtils.isEmpty(regAuthMap)) {
            authMap.put(SecurityUrlUtils.AuthCacheMapRegKey, JSON.toJSONString(regAuthMap));
        }
        redisUtils.delete(SecurityUrlUtils.AuthCacheKey);
        if (!CollectionUtils.isEmpty(authMap)) {
            redisUtils.mput(SecurityUrlUtils.AuthCacheKey, authMap);
        }
    }

    /**
     * 清空缓存
     */
    public static void removeCache(RedisUtils redisUtils) {
        redisUtils.delete(AuthCacheKey);
    }

    public static boolean getJSONType(String str) {
        boolean result = false;
        if (StringUtils.hasText(str)) {
            str = str.trim();
            if (str.startsWith("{") && str.endsWith("}")) {
                result = true;
            } else if (str.startsWith("[") && str.endsWith("]")) {
                result = true;
            }
        }
        return result;
    }

    private static Set<String> getAuthTypes(String url, RedisUtils redisUtils) {
        Set<String> authTypeSet = new HashSet<String>();
        Set<String> hashKeys = new HashSet<String>();
        hashKeys.add(url);
        hashKeys.add(SecurityUrlUtils.AuthCacheMapRegKey);
        List<String> authUrls = redisUtils.mget(SecurityUrlUtils.AuthCacheKey, hashKeys);

        if (!CollectionUtils.isEmpty(authUrls)) {
            for (String authUrl : authUrls) {
                if (getJSONType(authUrl)) {
                    DataMapEntity dme = JSON.parseObject(authUrl, DataMapEntity.class);
                    for (String regexUrl : dme.keySet()) {
                        if (RegexUtils.isAuthc(url, regexUrl)) {
                            String regexVal = (String) dme.get(regexUrl);
                            authTypeSet.addAll(StrSplitUtils.parse2set(regexVal, String.class));
                        }
                    }
                } else {
                    authTypeSet.addAll(StrSplitUtils.parse2set(authUrl, String.class));
                }
            }
        }
        return authTypeSet;
    }

    /**
     * 权限检验
     */
    public static LoginUserInfo check(String url, String token, RedisUtils redisUtils) {

        Set<String> authTypes = getAuthTypes(url, redisUtils);
        if (CollectionUtils.isEmpty(authTypes)) {
            throw new BusinessException(BaseReturnEnum.Security_Config_Error);
        }

        // 是否黑名单
        if (authTypes.contains(ApiAuthTypeEnum.Black_List.getCode())) {
            throw new BusinessException(BaseReturnEnum.NOT_AUTHC);
        }
        // 是否白名单
        if (authTypes.contains(ApiAuthTypeEnum.Black_List.getCode())) {
            LoginUserInfo user = AuthSecurityManager.check(AuthHandle.Anon, url, token, redisUtils);
            return user;
        }

        // 是否权限认证
        if (authTypes.contains(ApiAuthTypeEnum.Auth_List.getCode())) {
            LoginUserInfo user = AuthSecurityManager.check(AuthHandle.Authc, url, token, redisUtils);
            return user;
        }

        // 是否登录认证
        if (authTypes.contains(ApiAuthTypeEnum.Login_List.getCode())) {
            LoginUserInfo user = AuthSecurityManager.check(AuthHandle.Login, url, token, redisUtils);
            return user;
        }
        throw new BusinessException(BaseReturnEnum.Security_Config_Error);
    }


}
